package edu.cuit.zhuyimeng.uaa.service.impl;

import cn.dev33.satoken.secure.BCrypt;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.util.StrUtil;
import com.alicp.jetcache.Cache;
import com.alicp.jetcache.anno.CacheInvalidate;
import com.alicp.jetcache.anno.CacheInvalidateContainer;
import com.alicp.jetcache.anno.Cached;
import com.baomidou.dynamic.datasource.annotation.Master;
import com.baomidou.dynamic.datasource.annotation.Slave;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import edu.cuit.zhuyimeng.framework.common.exception.UpdateException;
import edu.cuit.zhuyimeng.framework.common.result.HttpStatusCodeConstants;
import edu.cuit.zhuyimeng.uaa.controller.vo.UserInfoVO;
import edu.cuit.zhuyimeng.uaa.convert.UserInfoConverter;
import edu.cuit.zhuyimeng.uaa.dal.mapper.RoleMapper;
import edu.cuit.zhuyimeng.uaa.dal.mapper.UserMapper;
import edu.cuit.zhuyimeng.uaa.dal.mapper.UserRoleMapper;
import edu.cuit.zhuyimeng.uaa.dal.po.RolePO;
import edu.cuit.zhuyimeng.uaa.dal.po.UserPO;
import edu.cuit.zhuyimeng.uaa.dal.po.UserRolePO;
import edu.cuit.zhuyimeng.uaa.enums.CacheConstants;
import edu.cuit.zhuyimeng.uaa.exception.AuthenticationException;
import edu.cuit.zhuyimeng.uaa.service.IUserService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * 用户服务实现
 */
@Service
@RequiredArgsConstructor
public class UserService implements IUserService {

    private final UserMapper userMapper;
    private final RoleMapper roleMapper;
    private final UserRoleMapper userRoleMapper;

    private final Cache<String,String> passwordCache;

    @Override
    public List<String> getPermissionsByLoginId(String loginId) {
        return StpUtil.getPermissionList(loginId);
    }

    @Override
    public String getRoleByLoginId(String loginId) {
        return StpUtil.getRoleList(loginId).get(0);
    }

    @Override
    @Slave
    public void login(String loginId, String password, Boolean rememberMe) {
        if (StpUtil.isLogin()) {
            throw new AuthenticationException("已登录，请勿重复登录", HttpStatusCodeConstants.FORBIDDEN);
        }
        String storedPassword = userMapper.selectPasswordByName(loginId);
        if (StrUtil.isBlankIfStr(storedPassword)) {
            throw new AuthenticationException("用户名不存在", HttpStatusCodeConstants.NOT_FOUND);
        }
        if (!BCrypt.checkpw(password,storedPassword)) {
            throw new AuthenticationException("用户名或密码错误", HttpStatusCodeConstants.FORBIDDEN);
        }
        StpUtil.login(loginId,rememberMe);
    }

    @Override
    public void logout() {
        StpUtil.logout();
    }

    @Override
    @Master
    public void register(String loginId, String nickname, String password, String email, String phone) {
        if (StpUtil.isLogin()) {
            throw new AuthenticationException("已登录，无法注册", HttpStatusCodeConstants.FORBIDDEN);
        }

        if (userMapper.selectOne(new LambdaQueryWrapper<UserPO>().select(UserPO::getName).eq(UserPO::getName,loginId)) != null) {
            throw new AuthenticationException("用户名已存在", HttpStatusCodeConstants.CONFLICT);
        }
        if (userMapper.selectOne(new LambdaQueryWrapper<UserPO>().select(UserPO::getNickname).eq(UserPO::getNickname,nickname)) != null) {
            throw new AuthenticationException("昵称已存在", HttpStatusCodeConstants.CONFLICT);
        }

        String hashedPassword = BCrypt.hashpw(password);

        UserPO user = new UserPO();
        user.setName(loginId);
        user.setNickname(nickname);
        user.setPassword(hashedPassword);
        user.setEmail(email);
        user.setPhone(Long.valueOf(phone));
        passwordCache.put(loginId,hashedPassword);

        userMapper.insert(user);
        userRoleMapper.insert(new UserRolePO(user.getId(),1));
    }

    @Override
    @Cached(name = CacheConstants.USERINFO_CACHE,key = "args[0]")
    @Slave
    public UserInfoVO getUserInfoByLoginId(String loginId) {
        return UserInfoConverter.convert(userMapper.selectUserByName(loginId));
    }

    @Override
    @Master
    @CacheInvalidateContainer({
            @CacheInvalidate(name = CacheConstants.PERM_CACHE,key = "args[0]"),
            @CacheInvalidate(name = CacheConstants.ROLE_CACHE,key = "args[0]"),
            @CacheInvalidate(name = CacheConstants.PASSWORD_CACHE,key = "args[0]"),
            @CacheInvalidate(name = CacheConstants.USERINFO_CACHE,key = "args[0]"),
    })
    public void deleteUser(String name) {
        UserPO userPO = userMapper.selectUserByName(name);
        if (userPO == null) {
            throw new UpdateException("用户不存在");
        }
        if (StpUtil.isLogin(userPO.getName())) {
            StpUtil.logout(userPO.getName());
        }
        userMapper.delete(new LambdaQueryWrapper<UserPO>().eq(UserPO::getName, name));
        //已加入外键约束
//        userRoleMapper.delete(new LambdaQueryWrapper<UserRolePO>().eq(UserRolePO::getUserId,userPO.getId()));

    }

    @Override
    @Master
    @CacheInvalidateContainer({
            @CacheInvalidate(name = CacheConstants.PERM_CACHE,key = "args[0]"),
            @CacheInvalidate(name = CacheConstants.ROLE_CACHE,key = "args[0]"),
            @CacheInvalidate(name = CacheConstants.USERINFO_CACHE,key = "args[0]"),
    })
    public void updateUserRole(String name, Integer roleId) {
        Long count = roleMapper.selectCount(new LambdaQueryWrapper<RolePO>().eq(RolePO::getId, roleId));
        if (count <= 0) {
            throw new UpdateException("角色不存在");
        }
        UserPO userPO = userMapper.selectUserByName(name);
        if (userPO == null) {
            throw new UpdateException("用户不存在");
        }
        userRoleMapper.update(new LambdaUpdateWrapper<UserRolePO>().eq(UserRolePO::getUserId,userPO.getId()).set(UserRolePO::getRoleId, roleId));

    }
}
